package com.xcity.game.activity.chips;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import com.xcity.Server;
import com.xcity.db.entity.Player;
import com.xcity.game.activity.ActivityService;
import com.xcity.game.activity2.ActivityIds;
import com.xcity.game.chat.ChatService;
import com.xcity.game.common.Cause;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.common.ItemResponse;
import com.xcity.game.common.MessageConst;
import com.xcity.game.common.PlayerPool;
import com.xcity.game.event.GameEvents;
import com.xcity.game.item.ItemException;
import com.xcity.game.item.ItemTemplate;
import com.xcity.game.mail.MailAttach;
import com.xcity.game.mail.MailService;
import com.xcity.game.player.PlayerService;
import com.xcity.game.player.cache.PlayerCacheService;
import com.xcity.game.relation.RelationService;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.push.NoticePush;
import com.xcity.pomelo.push.msg.ActivityStatePush;
import com.xcity.pomelo.push.msg.TipPush;
import com.xcity.pomelo.request.ActivityChipsCollectInfoRequest;
import com.xcity.pomelo.request.ActivityChipsCollectOperationRequest;
import com.xcity.pomelo.request.ActivityChipsCollectPresentRequest;
import com.xcity.pomelo.request.ActivityChipsCollectRewardRequest;
import com.xcity.pomelo.response.ActivityChipsCollectInfoResponse;
import com.xcity.pomelo.response.ActivityChipsCollectOperationResponse;
import com.xcity.pomelo.response.ActivityChipsCollectRewardResponse;
import com.xcity.pomelo.response.HintResponse;

import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.template.TemplateService;
import naga.x.game.time.DayListener;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Packet;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.ServiceException;
import naga.x.util.TimeUtils;

/**
 * 碎片拼图活动
 * @author yang.li
 *
 */
@OPHandler
public class ChipsCollectActivityService extends ActivityService implements DayListener, EventListener {

	protected ItemTemplate[] chips;
	protected ChipsCollectReward reward = new ChipsCollectReward(300000, 100, new ItemResponse(60040, 1));
	
	protected long beginTime = TimeUtils.parse("2017-01-19 21:20:00").getTime();
//	protected long beginTime = TimeUtils.parse("2017-01-19 20:40:00").getTime();
//	protected long endTime = TimeUtils.parse("2017-01-30 23:59:59").getTime();
	protected long endTime = TimeUtils.parse("2018-01-30 23:59:59").getTime();
	public static final int MAX_REWARD_TIMES = 10; // 活动期间最多可领奖次数
	
	private PlayerCacheService playerCacheService;
	
	@Override
	public void startup() throws ServiceException {
		playerCacheService = Objects.requireNonNull(App.getApp().getServiceManager().get(PlayerCacheService.class));
		TemplateService ts = App.getApp().getServiceManager().get(TemplateService.class);
		chips = new ItemTemplate[] {
				ts.get(ItemTemplate.class, 90013),
				ts.get(ItemTemplate.class, 90014),
				ts.get(ItemTemplate.class, 90015),
				ts.get(ItemTemplate.class, 90016),
				ts.get(ItemTemplate.class, 90017),
				ts.get(ItemTemplate.class, 90018),
				ts.get(ItemTemplate.class, 90019),
				ts.get(ItemTemplate.class, 90020),
				ts.get(ItemTemplate.class, 90021),
		};
		if (!isEnd()) {
			TimeUpdater.getInstance().addDayListener(this);
			App.getApp().getEventManager().register(this);
		} else {
			long delay = beginTime - TimeUpdater.getInstance().now();
			if (delay > 0) {
				App.getApp().getSchedule().schedule(new Runnable() {
					@Override
					public void run() {
						TimeUpdater.getInstance().addDayListener(ChipsCollectActivityService.this);
						App.getApp().getEventManager().register(ChipsCollectActivityService.this);
						Collection<Player> players = App.getApp().getServiceManager().get(PlayerService.class).getOnlinePlayers();
						Packet packet = new ActivityStatePush(ActivityIds.ACTIVITY_CHIPS_COLLECT, STATE_OPENED);
						for (Player player : players) {
							if (player.getLevel() >= GameStaticConfig.chipsCollectActivityOpenLvl) {
								player.send(packet);
							}
						}
					}
				}, delay, TimeUnit.MILLISECONDS);
			}
		}
	}

	@Override
	public void shutdown() throws ServiceException {
	}
	
	protected boolean isEnd() {
		long now = TimeUpdater.getInstance().now();
		return now >= endTime || now < beginTime;
	}
	
	@PomeloOP(PomeloRoute.CHIPS_COLLECT_ACTIVITY_INFO)
	protected void requestInfo(Session session, ActivityChipsCollectInfoRequest req) {
		Player player = session.getClient();
		session.send(new ActivityChipsCollectInfoResponse(req.getSerial(), player, reward, chips));
	}
	
	@PomeloOP(PomeloRoute.CHIPS_COLLECT_ACTIVITY_OPERATION)
	protected void requestOperation(Session session, ActivityChipsCollectOperationRequest req) {
		if (isEnd()) {
			session.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_NOT_BEGIN));
			return;
		}
		int index = req.getIndex();
		if (index < 0 || index >= chips.length) {
			session.send(new HintResponse(req.getSerial(), MessageConst.ILLEGAL_OPERATION));
			return;
		}
		if (req.getOp() == 0) {
			chipUnload(session, req);
		} else {
			chipLoad(session, req);
		}
	}
	
	protected void chipLoad(Session session, ActivityChipsCollectOperationRequest req) {
		int index = req.getIndex();
		Player player = session.getClient();
		int state = player.getPool().getIntValue(PlayerPool.PROPERTY_CHIPS_COLLECT_STATE);
		if ((state >> index & 1) == 1) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CHIPS_LOADED));
			return;
		}
		ItemTemplate chip = chips[index];
		if (!player.getBag().removeItem(chip.getId(), 1, Cause.CHIP_LOAD)) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CHIPS_NOT_ENOUGH));
			return;
		}
		state |= 1 << index;
		player.poolSet(PlayerPool.PROPERTY_CHIPS_COLLECT_STATE, state);
		session.send(new ActivityChipsCollectOperationResponse(req.getSerial(), player, index, chip.getId()));
		LOG.info("[CHIP LOAD]ID[{}]INDEX[{}]CHIP[{}]STATE[{}]", player.getId(), index, chip.getId(), state);
	}
	
	protected void chipUnload(Session session, ActivityChipsCollectOperationRequest req) {
		int index = req.getIndex();
		Player player = session.getClient();
		int state = player.getPool().getIntValue(PlayerPool.PROPERTY_CHIPS_COLLECT_STATE);
		if ((state >> index & 1) == 0) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CHIPS_UNLOADED));
			return;
		}
		ItemTemplate chip = chips[index];
		try {
			player.getBag().addItem(chip.getId(), 1, Cause.CHIP_UNLOAD);
		} catch (ItemException e) {
			session.send(new HintResponse(req.getSerial(), e.getMessage()));
			return;
		}
		state ^= 1 << index;
		player.poolSet(PlayerPool.PROPERTY_CHIPS_COLLECT_STATE, state);
		session.send(new ActivityChipsCollectOperationResponse(req.getSerial(), player, index, chip.getId()));
		LOG.info("[CHIP UNLOAD]ID[{}]INDEX[{}]CHIP[{}]STATE[{}]", player.getId(), index, chip.getId(), state);
	}
	
	@PomeloOP(PomeloRoute.CHIPS_COLLECT_ACTIVITY_REWARD)
	protected void requestReward(Session session, ActivityChipsCollectRewardRequest req) {
		if (isEnd()) {
			session.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_NOT_BEGIN));
			return;
		}
		Player player = session.getClient();
		int state = player.getPool().getIntValue(PlayerPool.PROPERTY_CHIPS_COLLECT_STATE);
		if (state != 0x1ff) { // 低9位全部为1，即9块碎片全部拼上
			session.send(new HintResponse(req.getSerial(), MessageConst.CHIPS_REWARD_NOT_FINISH));
			return;
		}
		if (player.getPool().getIntValue(PlayerPool.PROPERTY_CHIPS_COLLECT_REWARD_TIMES) >= MAX_REWARD_TIMES) {
			session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.ACTIVITY_REWARD_TIMES_EXCEED, MAX_REWARD_TIMES)));
			return;
		}
		player.poolSet(PlayerPool.PROPERTY_CHIPS_COLLECT_STATE, 0); // 重置状态
		int count = player.poolAdd(PlayerPool.PROPERTY_CHIPS_COLLECT_REWARD_TIMES, 1);
		reward.doReward(player);
		session.send(new ActivityChipsCollectRewardResponse(req.getSerial(), 0, count));
		
		String msg = MessageFormat.format(MessageConst.CHIPS_COLLECT_ACTIVITY_GOT_REWARD, player.getName());
		Server.broadcast(new NoticePush(NoticePush.NOTICE_MARQUEE, msg));
		App.getApp().getServiceManager().get(ChatService.class).sendSystemChat(msg);
	}
	
	@PomeloOP(PomeloRoute.CHIPS_COLLECT_ACTIVITY_PRESENT)
	protected void requestPresentChip(Session session, ActivityChipsCollectPresentRequest req) {
		if (isEnd()) {
			session.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_NOT_BEGIN));
			return;
		}
		int chipId = req.getChip();
		int index = indexOfChips(chipId);
		if (index < 0) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CHIPS_NOT_ENOUGH));
			return;
		}
//		Player friend = App.getApp().getServiceManager().get(ActorService.class).find(req.getId());
		Player friend = playerCacheService.find(req.getId());
		if (friend == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PLAYER_NOT_EXIST));
			return;
		}
		Player player = session.getClient();
		RelationService service = App.getApp().getServiceManager().get(RelationService.class);
		if (!service.isFriend(player, friend)) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CANT_PRESENT_TO_NOT_FRIEND));
			return;
		}
		int count = req.getCount();
		if (!player.getBag().removeItem(chipId, count, Cause.PRESENT)) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CHIPS_NOT_ENOUGH));
			return;
		}
		MailService mailService = App.getApp().getServiceManager().get(MailService.class);
		MailAttach attach = new MailAttach();
		attach.addItem(chipId, count);
		mailService.sendSystemMail(
				friend.getId(),
				MessageConst.RECEIVED_CHIPS_MAIL_TITLE,
				MessageFormat.format(MessageConst.RECEIVED_CHIPS_MAIL_CONTENT, player.getName(), player.getId(), new Date(), count),
				attach);
		if (friend.isOnline()) {
			friend.send(new TipPush(MessageFormat.format(MessageConst.RECEIVED_CHIPS_HINT, player.getName(), count)));
		}
		session.send(new ActivityChipsCollectOperationResponse(req.getSerial(), player, index, chipId));
		LOG.info("[CHIP PRESENT]ID[{}]FRIEND[{}]INDEX[{}]CHIP[{}]COUNT[{}]", player.getId(), friend.getId(), index, chipId, count);
	}
	
	private int indexOfChips(int chipId) {
		ItemTemplate[] _chips = chips;
		for (int i = 0, len = _chips.length; i < len; i++) {
			if (_chips[i].getId() == chipId) {
				return i;
			}
		}
		return -1;
	}

	@Override
	public boolean dayChanged() {
		if (isEnd()) {
			App.getApp().getEventManager().unRegister(this);
			Server.broadcast(new ActivityStatePush(ActivityIds.ACTIVITY_CHIPS_COLLECT, STATE_CLOSED));
			return false;
		}
		return true;
	}

	@Override
	public int[] getEventTypes() {
		return new int[] { GameEvents.EVENT_PLAYER_LOADED, GameEvents.EVENT_PLAYER_LEVEL_UP };
	}

	@Override
	public void handleEvent(Event event) {
		if (!isEnd()) {
			Player player = event.getParameter(0);
			Integer oldLvl = event.getParameter(1); // EVENT_PLAYER_LOADED -> null
			if (player.getLevel() >= GameStaticConfig.chipsCollectActivityOpenLvl
					&& (oldLvl == null || oldLvl.intValue() < GameStaticConfig.chipsCollectActivityOpenLvl)) {
				player.send(new ActivityStatePush(ActivityIds.ACTIVITY_CHIPS_COLLECT, STATE_OPENED));
			}
		}
	}

}
